{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### MCP Server Types\n",
    "\n",
    "This notebook contains simplr projects of using MCP servers - locally hosted and online MCP servers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#importing required libraries\n",
    "from agents import Agent, Runner, trace\n",
    "from agents.mcp import MCPServerStdio\n",
    "from agents.extensions.models.litellm_model import LitellmModel\n",
    "\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from IPython.display import Markdown, display\n",
    "from datetime import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv(override=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "api_key = os.getenv(\"AMAZON_BEDROCK_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_name = \"us.anthropic.claude-3-7-sonnet-20250219-v1:0\"\n",
    "model=LitellmModel(model=model_name, api_key=api_key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### The first type of MCP Server: runs locally.\n",
    "\n",
    "This is a knowledge-graph based memory.\n",
    "\n",
    "It's a persistent memory store of entities, observations about them, and relationships between them.\n",
    "\n",
    "https://github.com/modelcontextprotocol/servers/tree/main/src/memory\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "env = {\n",
    "    \"LIBSQL_URL\": \"file:./memory/ian.db\",\n",
    "    \"PATH\": \"/usr/bin/node\" + os.environ[\"PATH\"]\n",
    "}\n",
    "params = {\n",
    "    \"command\": \"npx\",\n",
    "    \"args\": [\"-y\", \"mcp-memory-libsql\"],\n",
    "    \"env\": env,\n",
    "}\n",
    "\n",
    "async with MCPServerStdio(params=params, client_session_timeout_seconds=30) as server:\n",
    "    mcp_tools = await server.list_tools()\n",
    "\n",
    "mcp_tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "instructions = \"You use your entity tools as a persistent memory to store and recall information about your conversations.\"\n",
    "request = \"My name's Ian. I'm an DevOps eng currently learning LLM engineering. I'm currently learning MCP protocol. \\\n",
    "MCP is a protocol for connecting agents with tools, resources and prompt templates, and makes it easy to integrate AI agents with capabilities.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "async with MCPServerStdio(params=params, client_session_timeout_seconds=30) as mcp_server:\n",
    "    agent = Agent(\n",
    "        name=\"simple_agent\",\n",
    "        instructions=instructions,\n",
    "        model=model,\n",
    "        mcp_servers=[mcp_server]\n",
    "    )\n",
    "\n",
    "    with trace(\"conversation\"):\n",
    "        result = await Runner.run(agent, request)\n",
    "    display(Markdown(result.final_output))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "memory_test_prompt = \"My name's Ian. What do you know about me?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "async with MCPServerStdio(params=params, client_session_timeout_seconds=30) as mcp_server:\n",
    "    agent = Agent(name=\"agent\", instructions=instructions, model=model, mcp_servers=[mcp_server])\n",
    "    with trace(\"conversation\"):\n",
    "        result = await Runner.run(agent, memory_test_prompt)\n",
    "    display(Markdown(result.final_output))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Remote MCP Server\n",
    "\n",
    "A remote MCP server is also called hosted MCP server or managed MCP server.\n",
    "\n",
    "It's not a common model for using or sharing MCP servers, and there isn't a standard way to discover remote MCP servers.\n",
    "\n",
    "Anthropic lists some remote MCP servers, but these are for paid applications with business users:\n",
    "\n",
    "https://docs.anthropic.com/en/docs/agents-and-tools/remote-mcp-servers\n",
    "\n",
    "CloudFlare has tooling for you to create and deploy your own remote MCP servers, but this does not seem to be a common practice:\n",
    "\n",
    "https://developers.cloudflare.com/agents/guides/remote-mcp-server/\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### polygon.io\n",
    "\n",
    "Polygon.io is a hugely popular financial data provider. It has a free plan and a paid plan. And it also has an MCP Server!\n",
    "\n",
    "Check up on docs and pricing:\n",
    "\n",
    "https://polygon.io\n",
    "\n",
    "Generate api key and store in .env file.\n",
    "\n",
    "`POLYGON_API_KEY=xxxx`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv(override=True)\n",
    "polygon_api_key = os.getenv(\"POLYGON_API_KEY\")\n",
    "if not polygon_api_key:\n",
    "    print(\"POLYGON_API_KEY is not set\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from polygon import RESTClient\n",
    "\n",
    "client = RESTClient(polygon_api_key)\n",
    "client.get_previous_close_agg(\"AAPL\")[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Python module that caches end of day prices\n",
    "\n",
    "Python module `market.py` that uses this API to look up share prices.\n",
    "\n",
    "But the free API is quite heavily rate limited - so I've been a bit sneaky; when you ask for a share price, this function retrieves the entire end-of-day equity market, and caches it in our database."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from market import get_share_price\n",
    "\n",
    "get_share_price(\"AAPL\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# no rate limiting concerns!\n",
    "\n",
    "for i in range(1000):\n",
    "    get_share_price(\"AAPL\")\n",
    "get_share_price(\"AAPL\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Market MCP Server\n",
    "\n",
    "Just as we did with accounts.py; see `market_server.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "params = {\n",
    "    \"command\": \"uv\", \n",
    "    \"args\": [\"run\", \"market_server.py\"]\n",
    "    }\n",
    "async with MCPServerStdio(params=params, client_session_timeout_seconds=60) as server:\n",
    "    mcp_tools = await server.list_tools()\n",
    "mcp_tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "instructions = \"You answer questions about the stock market.\"\n",
    "request = \"How is apple performing right now compared to amazon?\"\n",
    "\n",
    "async with MCPServerStdio(params=params, client_session_timeout_seconds=60) as mcp_server:\n",
    "    agent = Agent(\n",
    "        name=\"market_agent\", \n",
    "        instructions=instructions, \n",
    "        model=model, \n",
    "        mcp_servers=[mcp_server]\n",
    "    )\n",
    "    \n",
    "    with trace(\"share_price_conversation\"):\n",
    "        result = await Runner.run(agent, request)\n",
    "    display(Markdown(result.final_output))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
